
import os
import  os.path
import pandas as pd
from datatoolsobj.utils import create_dir_recursion
from tqdm import tqdm


class DumpWorkFiles():
    """
    根据使用表配置表及多行配置表的内容，对要用到的数据文件进行转储。如果表头行为单行，则直接进行转储。如果表头行为多行，则先进行多行处理，分析出多行转单行的方式，然后转储为单行。
    """

    def __init__(self, used_sheets, mode="new", used_columns_dict=None, transfer_work_dir="../数据转储"):
        """
        创建一个用于将使用到的单表头行数据文件及多表头行数据文件转储在指定目录的对象。
        :param used_sheets: 根据findUseSheets获取的单行表头数据文件路径结构或由MultiLineHdrHub生成的多行表头文件路径结构。
        :param mode: 用于指定转储方式。all表示如果指定目录下存在相同文件，直接覆盖。new表示相同文件不覆盖，只拷贝新增文件。
        :param used_columns_pos: 由MultiLineHdrHub生成的多行表头文件路径结构中，用到的规范列结构字典。
        :param transfer_work_dir: 用于放置转储文件的目录。
        """
        # 生成模式参数
        self._mode = mode
        if mode not in ['all', 'new']:
            self._mode = 'all'

        # 设置转储文件目录，并生成目录
        self._transfer_work_dir = transfer_work_dir
        create_dir_recursion(transfer_work_dir)

        # 只对配置为使用的文件进行转储
        # 同时处理单行和多行表头文件的转储，根据配置文件中单行配置进行区分
        self._used_columns_dict = used_columns_dict
        self._used_sheets = used_sheets.loc[used_sheets['是否使用'].isin(['是', 'Y', True, 'TRUE', 'True'])]

        # # 根据参数判断要转储的文件是单行转储还是多行转储
        # # 为了简化流程的复杂性，每次处理单行或多行中的一种，故对于包含多行文件的情况，此函数需要分开运行两次
        # if used_columns_dict is None:
        #     # 当前为单行表头文件为单行
        #     used_sheets = used_sheets.loc[used_sheets['是否使用'].isin(['是', 'Y', True, 'TRUE', 'True'])]
        #     # 只对配置参数为单行列名的文件进行转储
        #     self._used_sheets = used_sheets.loc[used_sheets['单行列名'].isin(['是', 'Y', True, 'TRUE', 'True'])]
        #     self._used_columns_dict = None
        # else:
        #     # 当前执行的是多行转储
        #     self._used_columns_dict = used_columns_dict
        #     # 只对配置参数为多行列名的文件进行转储
        #     self._used_sheets = used_sheets.loc[~used_sheets['单行列名'].isin(['是', 'Y', True, 'TRUE', 'True'])]

    def _getFileScrPath(self, src_path,src_flag = '/原始数据/'):
        """
        根据文件原始数据的位置，或取原始数据中数据的相对目录的全路径。
        :param src_path:文件原始数据中的原始路径。
        :param src_flag:能够从src_path中明显区分路径根目录的标记，标记要从路径起始开始计算，由于数据通常放置于原始数据文件夹中，故默认使用它。
        """
        path_pos = src_path.find(src_flag) + len(src_flag)
        return src_path[path_pos:]

    def dumpWorkFiles(self):
        """
        转储文件的主要方法。
        """
        # 遍历使用多行配置的文件路径
        sheets_gp = self._used_sheets.groupby("文件路径")
        with tqdm(total=len(sheets_gp)) as pbar:
            count = 0
            for file_path, file_data in sheets_gp:
                count += 1
                pbar.set_description("转存进度")
                pbar.update(1)
                # 获取原始文件中的文件路径中的目录结构
                relat_path = self._getFileScrPath(file_path)
                # 购建转储目录的目标路径
                dest_path_dir = os.path.dirname(os.path.join(self._transfer_work_dir, relat_path))
                create_dir_recursion(dest_path_dir)
                # 针对每个Excel文件，生成一个工作簿，然后分Sheet表保存。
                dest_path = os.path.join(self._transfer_work_dir, relat_path)
                # 如果指定模式为‘new’，则只创建新的不存在的文件。
                if os.path.exists(dest_path) and self._mode=='new':
                    continue
                writer = pd.ExcelWriter(dest_path, engine='openpyxl')
                # 遍历每个工作表的数据，进行转储保存
                for index, row in file_data.iterrows():
                    file_id = row['文件编号']
                    #file_name = row['文件名称']
                    sheet_name = row['Sheet表名']
                    if self._used_columns_dict and (file_id in self._used_columns_dict):
                        # 处理多行表头的情况
                        if file_id not in self._used_columns_dict:
                            raise KeyError("文件编号为【{}】的文件配置为多行，但没有多行列名数据！".format(file_id))
                        # 根据used_columns_dict中的数据，分析出要使用的列索引
                        used_cols = [int(item[2]) for item in self._used_columns_dict[file_id]]
                        # 根据used_columns_dict中的数据，分析出要使用的列名列表
                        used_cols_name = [item[0] for item in self._used_columns_dict[file_id]]
                        # 获取表头行的最大位置，用于做有效数据读取的行定位
                        max_hdr_row = self._used_columns_dict[file_id][0][3]
                        # 读取有效数据
                        src_data = pd.read_excel(file_path, sheet_name=sheet_name, header=None, dtype="object",skiprows=int(max_hdr_row + 1), usecols=list(used_cols))
                        # 设置数据的列名
                        src_data.columns = used_cols_name
                        # 将数据连同列名同时保存在目标文件中的Sheet表中。
                        src_data.to_excel(writer, sheet_name=sheet_name, index=False)
                    else:
                        # 配置文件中为单行的Sheet表的转储处理。
                        # 读取所有数据，不进行任何处理，不设置表头、索引的读取
                        src_data = pd.read_excel(file_path, sheet_name=sheet_name, header=None, dtype="object")
                        # 读取的文件原样保存
                        src_data.to_excel(writer, sheet_name=sheet_name, index=False, header=None)
                writer._save()
                writer.close()